|
|
| |
|
Page 1 of 1
|
[ 10 posts ] |
|
| Author |
Message |
|
Paul Siramy
|
Posted: Fri Nov 22, 2002 3:32 am Post subject: ds1_load() D2Common.6FD76520 1.09b |
|
Age: 35 Joined: Sat May 25, 2002 2:39 pm Posts: 2738 Location: La Garenne Colombes (near Paris) Gender:
|
Thanks go to
- Myhrginoc, he provide me the asm code (I didn't know anything about Ollydbg 2 weeks ago), and also made the first comments that really helped me to start.
- SVR, for having done half of the work, always beeing here when I lacked some asm knowledge, and having make some errors (that way I can say "I helped too"
)
DESCRIPTION :
This function load a .DS1 (a map of the game). Extracted from D2Common v1.09 b. In the v 1.09 d it's at 6FD76530 (just + 00000010 than in 1.09 b).
This function takes one parameter on the stack, the pointer to the ds1 file name string. It also takes parameters in ECX and EDX. ECX is an offset to the DS1_INFO structure ('this' object in C++).
STRUCTURES USED :
DS1_INFO ======== + 00 dword UNK_TYPE : type of the unknown layer 0 means no unknown layer and no unknown datas between the Objects and Paths datas. 1 or 2 means there's such datas. + 04 dword DS1_PTR : DS1 file pointer in heap + 08 dword ? : unused + 0C dword WIDTH : in # of tiles + 10 dword HEIGHT : in # of tiles + 14 dword WALL_NUM : # of walls layers + 18 dword FLOOR_NUM : # of floor layers + 1C dword OFF_DIR_1 : pointer to direction layer 1 + 20 dword OFF_DIR_2 : pointer to direction layer 2 + 24 dword OFF_DIR_3 : pointer to direction layer 3 + 28 dword OFF_DIR_4 : pointer to direction layer 4 + 2C dword OFF_WALL_1 : pointer to wall layer 1 + 30 dword OFF_WALL_2 : pointer to wall layer 2 + 34 dword OFF_WALL_3 : pointer to wall layer 3 + 38 dword OFF_WALL_4 : pointer to wall layer 4 + 3C dword OFF_FLOOR_1 : pointer to floor layer 1 + 40 dword OFF_FLOOR_2 : pointer to floor layer 2 + 44 dword OFF_SHAD : pointer to shadow layer + 48 dword OFF_UNK : pointer to unknown layer (something to make groups of tiles I think) + 4C dword UNK_NUM : # of lines in the unknown datas, something to do with the Unknown layer + 50 dword UNK_PTR : pointer for storing these unknown lines, table of UNK_NUM elements of UNK_STRUCT + 54 dword START_OBJ_PTR : pointer to 1st element of the linked OBJECT structures
OBJECT ====== (I'm not sure for these 3 first datas) + 00 dword ID ? : original ID + 04 dword NEW_ID ? : new ID after possible modifications + 08 dword VERSION ? : version of the ds1
+ 0C dword OBJ_X : X coordinate in # of sub-tiles + 10 dword OBJ_Y : Y coordinate in # of sub-tiles + 14 dword FLAGS : flags of this object + 18 dword PATH_PTR : pointer to a simple PATHS_INFO structure, NULL if no paths for this object + 1C dword NEXT_PTR : pointer to next OBJECT in the linked list, NULL if none
PATHS_INFO ========== + 00 dword ACTION_NUM : # of actions for this NPC + 04 dword ACTION_PTR : pointer to a table of ACTION structure
ACTION ======= + 00 dword ACTION_CODE : action to do at these coordinates (default 1) + 04 dword PATH_X : X coordinate in # of sub-tiles + 08 dword PATH_Y : Y coordinate in # of sub-tiles
UNK_STRUCT ========== + 00 dword DW_1 : unknown dword 1 + 04 dword DW_2 : unknown dword 2 + 08 dword DW_3 : unknown dword 3 + 0C dword DW_4 : unknown dword 4 + 10 dword DW_5 : unknown dword 5 (only fill if VERSION > 13) + 14 dword ? : unused
LOCAL VARIABLES (on stack) :Some are used for almost anything, so these infos won't be very usefull in fact SS:[ESP+10] BYTE CODE [4] string of 4 characters, or a dword ? SS:[ESP+14] dword VERSION version of the ds1 SS:[ESP+18] dword DIR_READ # of direction layers read SS:[ESP+1C] dword TMP / TYPE # of tiles in 1 layer, object's type SS:[ESP+20] dword ACT act range from 0 to 4, default = 0 SS:[ESP+24] dword OBJ_NUM / NPC_NUM # of objects / # of NPC paths SS:[ESP+2C] dword CUR_DIR_OFF / NEW_ID pointer to current direction offset data in INFO / New ID of an object
_________________ DT1 Tools - DS1 Editor - MPQ list file - Extracting D2 Animation tutorial
"Sorry I can't give you offsets or anything, my dlls are always very mutant compared to what's in the release" - Isolde, aka Peter Hu, 30 Jun 2002
Last edited by Paul Siramy on Fri Nov 22, 2002 3:41 am, edited 1 time in total.
|
|
| Top |
|
 |
|
Paul Siramy
|
Posted: Fri Nov 22, 2002 3:33 am Post subject: |
|
Age: 35 Joined: Sat May 25, 2002 2:39 pm Posts: 2738 Location: La Garenne Colombes (near Paris) Gender:
|
READ DS1 HEADER :
6FD76520 /$ 83EC 18 SUB ESP,18 ; make 6 dword local variables 6FD76523 |. 53 PUSH EBX ; save EBX 6FD76524 |. 55 PUSH EBP ; save EBP 6FD76525 |. 56 PUSH ESI ; save ESI 6FD76526 |. 57 PUSH EDI ; save EDI 6FD76527 |. 8BC2 MOV EAX,EDX ; EAX = parameter 2 6FD76529 |. 8BD9 MOV EBX,ECX ; EBX = parameter 1 ; This parameter is 'this' (DS1_INFO)
6FD7652B |. 8B5424 2C MOV EDX,DWORD PTR SS:[ESP+2C] ; EDX = ? 6FD7652F |. 68 1C040000 PUSH 41C ; PUSH 1052 6FD76534 |. 68 EC46DD6F PUSH D2Common.6FDD46EC ; ASCII "C:\Projects\Diablo2\Source\D2Common\DRLG\Preset.cpp" 6FD76539 |. 6A 00 PUSH 0 ; PUSH 0 6FD7653B |. 8BC8 MOV ECX,EAX ; ECX = parameter 2 6FD7653D |. E8 62D30300 CALL D2Common.6FDB38A4 ; This call loads a DS1 file to heap, ; EAX returns with heap pointer
6FD76542 |. 8BF0 MOV ESI,EAX ; Heap pointer points to VERSION 6FD76544 |. 8973 04 MOV DWORD PTR DS:[EBX+4],ESI ; save DS1_PTR 6FD76547 |. 8B46 04 MOV EAX,DWORD PTR DS:[ESI+4] ; EAX = WIDTH 6FD7654A |. 8B3E MOV EDI,DWORD PTR DS:[ESI] ; EDI = VERSION 6FD7654C |. 83C6 04 ADD ESI,4 ; move pointer to WIDTH 6FD7654F |. 83C6 04 ADD ESI,4 ; move pointer to HEIGHT 6FD76552 |. 8943 0C MOV DWORD PTR DS:[EBX+C],EAX ; save WIDTH 6FD76555 |. C74424 20 00000000 MOV DWORD PTR SS:[ESP+20],0 ; ACT = 0 6FD7655D |. 897C24 14 MOV DWORD PTR SS:[ESP+14],EDI ; save VERSION 6FD76561 |. 8B0E MOV ECX,DWORD PTR DS:[ESI] ; ECX = HEIGHT 6FD76563 |. 83C6 04 ADD ESI,4 ; move pointer to next data 6FD76566 |. 83FF 08 CMP EDI,8 ; VERSION = 8 ? 6FD76569 |. 894B 10 MOV DWORD PTR DS:[EBX+10],ECX ; save HEIGHT 6FD7656C |. 7C 16 JL SHORT D2Common.6FD76584 ; VERSION < 8 ==> goto ACT_DONE
; else here VERSION >= 8 ; so current data = ACT
6FD7656E |. 8B06 MOV EAX,DWORD PTR DS:[ESI] ; EAX = ACT 6FD76570 |. 83C6 04 ADD ESI,4 ; move pointer to next data 6FD76573 |. 83F8 04 CMP EAX,4 ; ACT = 4 ? 6FD76576 |. 894424 20 MOV DWORD PTR SS:[ESP+20],EAX ; save ACT 6FD7657A |. 7E 08 JLE SHORT D2Common.6FD76584 ; ACT <= 4 ==> goto ACT_DONE
6FD7657C |. C74424 20 04000000 MOV DWORD PTR SS:[ESP+20],4 ; else replace the save value of ACT by 4
ACT_DONE : ========== 6FD76584 |> 83FF 0A CMP EDI,0A ; VERSION = 10 ? 6FD76587 |. C703 00000000 MOV DWORD PTR DS:[EBX],0 ; UNK_TYPE = 0 6FD7658D |. 7C 07 JL SHORT D2Common.6FD76596 ; VERSION < 10 ==> goto UNK_TYPE_DONE
; else here VERSION >= 10 ; so current data = UNK_TYPE
6FD7658F |. 8B16 MOV EDX,DWORD PTR DS:[ESI] ; EDX = UNK_TYPE 6FD76591 |. 83C6 04 ADD ESI,4 ; move pointer to next data 6FD76594 |. 8913 MOV DWORD PTR DS:[EBX],EDX ; save UNK_TYPE
UNK_TYPE_DONE : =============== 6FD76596 |> 83FF 03 CMP EDI,3 ; VERSION = 3 ? 6FD76599 |. 7C 19 JL SHORT D2Common.6FD765B4 ; VERSION < 3 ==> goto FILE_STRINGS_DONE
; else here VERSION >= 3 ; so current data = NUM_FILES
6FD7659B |. 8B06 MOV EAX,DWORD PTR DS:[ESI] ; EAX = NUM_FILES 6FD7659D |. 83C6 04 ADD ESI,4 ; ESI points to the first file string position ; or to WALL_NUM if no strings.
6FD765A0 |. 85C0 TEST EAX,EAX ; NUM_FILES positive ? 6FD765A2 |. 7E 10 JLE SHORT D2Common.6FD765B4 ; NUM_FILES <= 0 ==> goto FILE_STRINGS_DONE 6FD765A4 |. 8BE8 MOV EBP,EAX ; EBP = NUM_FILES
6FD765A6 |> 8BCE /MOV ECX,ESI ; This loop gets the length of each file string 6FD765A8 |. E8 A0D30300 |CALL D2Common.6FDB394D ; and moves a pointer to the first position past 6FD765AD |. 4D |DEC EBP ; that string's null terminator 6FD765AE |. 8D7406 01 |LEA ESI,DWORD PTR DS:[ESI+EAX+1] 6FD765B2 |.^75 F2 \JNZ SHORT D2Common.6FD765A6 ; Once fully looped, ESI points to WALL_NUM
FILE_STRINGS_DONE : =================== 6FD765B4 |> 8B6B 10 MOV EBP,DWORD PTR DS:[EBX+10] ; EBP = HEIGHT 6FD765B7 |. 8B43 0C MOV EAX,DWORD PTR DS:[EBX+C] ; EAX = WIDTH 6FD765BA |. 45 INC EBP ; HEIGHT ++ 6FD765BB |. 40 INC EAX ; WIDTH ++ 6FD765BC |. 0FAFE8 IMUL EBP,EAX ; signed multiplication of WIDTH per HEIGHT ; EBP = # of tiles in 1 layer
6FD765BF |. 83FF 09 CMP EDI,9 ; VERSION = 9 ? 6FD765C2 |. 896C24 1C MOV DWORD PTR SS:[ESP+1C],EBP ; TMP = # of tiles in 1 layer ; note : not used
6FD765C6 |. 7C 08 JL SHORT D2Common.6FD765D0 ; VERSION < 9 ==> goto NO_SPECIAL_SKIP
6FD765C8 |. 83FF 0E CMP EDI,0E ; VERSION = 14 ? 6FD765CB |. 7D 03 JGE SHORT D2Common.6FD765D0 ; VERSION >= 14 ==> goto NO_SPECIAL_SKIP
; else here VERSION is between 9 and 13 inclusive
6FD765CD |. 83C6 08 ADD ESI,8 ; skip 2 dwords
NO_SPECIAL_SKIP : ================= 6FD765D0 |> 83FF 04 CMP EDI,4 ; VERSION = 4 ? 6FD765D3 |. 7C 65 JL SHORT D2Common.6FD7663A ; VERSION < 4 ==> goto OFFSETS_VERSION_<_4
; else here VERSION >= 4
6FD765D5 |. 8B0E MOV ECX,DWORD PTR DS:[ESI] ; ECX = WALL_NUM 6FD765D7 |. 83C6 04 ADD ESI,4 ; move pointer to next data 6FD765DA |. 83FF 10 CMP EDI,10 ; VERSION = 16 ? 6FD765DD |. 894B 14 MOV DWORD PTR DS:[EBX+14],ECX ; save WALL_NUM 6FD765E0 |. 7C 0A JL SHORT D2Common.6FD765EC ; VERSION < 16 ==> goto FLOOR_NUM_DEFAULT
; else here VERSION >= 16
6FD765E2 |. 8B16 MOV EDX,DWORD PTR DS:[ESI] ; EDX = FLOOR_NUM 6FD765E4 |. 83C6 04 ADD ESI,4 ; move pointer to next data 6FD765E7 |. 8953 18 MOV DWORD PTR DS:[EBX+18],EDX ; save FLOOR_NUM 6FD765EA |. EB 07 JMP SHORT D2Common.6FD765F3 ; goto WALL_OFFSETS
FLOOR_NUM_DEFAULT : ================== 6FD765EC |> C743 18 01000000 MOV DWORD PTR DS:[EBX+18],1 ; save a default value for FLOOR_NUM : 1
WALL_OFFSETS : ==============
VERSION >= 16. Note : WALL layers are in fact 2 layers, first one have the usual Prop1, Prop2, Prop3, Prop4 datas of each Tiles, then the immediatly next layer have the Direction of each Tiles. Here we save the offsets of the WALL layers (props and directions), for accessing them easily later.
6FD765F3 |> 8B43 14 MOV EAX,DWORD PTR DS:[EBX+14] ; EAX = WALL_NUM 6FD765F6 |. 33D2 XOR EDX,EDX ; EDX = 0 6FD765F8 |. 85C0 TEST EAX,EAX ; WALL_NUM positive ? 6FD765FA |. 7E 1C JLE SHORT D2Common.6FD76618 ; WALL_NUM <= 0 ==> goto FLOOR_OFFSETS
; else here WALL_NUM > 0
6FD765FC |. 8D0CAD 00000000 LEA ECX,DWORD PTR DS:[EBP*4] ; ECX = # of * BYTES * in 1 layer 6FD76603 |. 8D43 1C LEA EAX,DWORD PTR DS:[EBX+1C] ; EAX = address of OFF_DIR_1
; currently, ESI is pointing to the 1st tile ; of the 1st WALL layer
6FD76606 |> 8970 10 /MOV DWORD PTR DS:[EAX+10],ESI ; save OFF_WALL_x 6FD76609 |. 03F1 |ADD ESI,ECX ; move pointer to next layer 6FD7660B |. 8930 |MOV DWORD PTR DS:[EAX],ESI ; save OFF_DIR_x 6FD7660D |. 03F1 |ADD ESI,ECX ; move pointer to next layer 6FD7660F |. 42 |INC EDX ; EDX ++ 6FD76610 |. 83C0 04 |ADD EAX,4 ; move EAX to next OFF_DIR_x data 6FD76613 |. 3B53 14 |CMP EDX,DWORD PTR DS:[EBX+14] ; # of WALL layers read = WALL_NUM ? 6FD76616 |.^7C EE \JL SHORT D2Common.6FD76606 ; # of WALL layers read < WALL_NUM ==> loop
FLOOR_OFFSETS : =============== Here we save the offsets of the FLOOR layers (Prop1 thru 4)
6FD76618 |> 8B43 18 MOV EAX,DWORD PTR DS:[EBX+18] ; EAX = FLOOR_NUM 6FD7661B |. 33C9 XOR ECX,ECX ; ECX = 0 6FD7661D |. 85C0 TEST EAX,EAX ; FLOOR_NUM positive ? 6FD7661F |. 7E 3B JLE SHORT D2Common.6FD7665C ; FLOOR_NUM <= 0 ==> goto READ_TILES
; else here FLOOR_NUM > 0
6FD76621 |. 8D14AD 00000000 LEA EDX,DWORD PTR DS:[EBP*4] ; EDX = # of * BYTES * in 1 layer 6FD76628 |. 8D43 3C LEA EAX,DWORD PTR DS:[EBX+3C] ; EAX = address of OFF_FLOOR_1 in INFO
; currently, ESI is pointing to the 1st tile ; of the 1st FLOOR layer
6FD7662B |> 8930 /MOV DWORD PTR DS:[EAX],ESI ; save OFF_FLOOR_x 6FD7662D |. 03F2 |ADD ESI,EDX ; move pointer to next layer 6FD7662F |. 41 |INC ECX ; ECX ++ 6FD76630 |. 83C0 04 |ADD EAX,4 ; move EAX to next OFF_FLOOR_x data 6FD76633 |. 3B4B 18 |CMP ECX,DWORD PTR DS:[EBX+18] ; # of FLOOR layers read = FLOOR_NUM ? 6FD76636 |.^7C F3 \JL SHORT D2Common.6FD7662B ; # of FLOOR layers read < FLOOR_NUM ==> loop
6FD76638 |. EB 22 JMP SHORT D2Common.6FD7665C ; goto READ_TILES
OFFSETS_VERSION_<_4 : =====================
if VERSION < 4, then we'll have hardcoded layers, in that order : * WALL 1 * FLOOR 1 (not direction !) * DIRECTION 1 * UNKNOWN layer * SHADOW layer (handle later)
6FD7663A |> 8D04AD 00000000 LEA EAX,DWORD PTR DS:[EBP*4] ; EAX = # of * BYTES * in 1 layer 6FD76641 |. 8973 2C MOV DWORD PTR DS:[EBX+2C],ESI ; current address in OFF_WALL_1 6FD76644 |. 03F0 ADD ESI,EAX ; move pointer to next layer 6FD76646 |. C743 14 01000000 MOV DWORD PTR DS:[EBX+14],1 ; WALL_NUM = 1 6FD7664D |. 8973 3C MOV DWORD PTR DS:[EBX+3C],ESI ; current address in OFF_FLOOR_1 6FD76650 |. 03F0 ADD ESI,EAX ; move pointer to next layer 6FD76652 |. 8973 1C MOV DWORD PTR DS:[EBX+1C],ESI ; current address in OFF_DIR_1 6FD76655 |. 03F0 ADD ESI,EAX ; move pointer to next layer 6FD76657 |. 8973 48 MOV DWORD PTR DS:[EBX+48],ESI ; current address in OFF_UNK 6FD7665A |. 03F0 ADD ESI,EAX ; move pointer to next layer
_________________ DT1 Tools - DS1 Editor - MPQ list file - Extracting D2 Animation tutorial
"Sorry I can't give you offsets or anything, my dlls are always very mutant compared to what's in the release" - Isolde, aka Peter Hu, 30 Jun 2002
|
|
| Top |
|
 |
|
Paul Siramy
|
Posted: Fri Nov 22, 2002 3:34 am Post subject: |
|
Age: 35 Joined: Sat May 25, 2002 2:39 pm Posts: 2738 Location: La Garenne Colombes (near Paris) Gender:
|
CONVERT DIRECTIONS / SHADOW LAYER / UNKNON LAYER :
READ_TILES : ============ 6FD7665C |> 83FF 07 CMP EDI,7 ; VERSION = 7 ? 6FD7665F |. 7D 56 JGE SHORT D2Common.6FD766B7 ; VERSION >= 7 ==> goto ALL_DIR_CONV_DONE
; else here VERSION < 7 ; we'll convert direction values !
6FD76661 |. 8B43 14 MOV EAX,DWORD PTR DS:[EBX+14] ; EAX = WALL_NUM 6FD76664 |. C74424 18 00000000 MOV DWORD PTR SS:[ESP+18],0 ; DIR_READ = 0 6FD7666C |. 85C0 TEST EAX,EAX ; WALL_NUM positive ? 6FD7666E |. 7E 47 JLE SHORT D2Common.6FD766B7 ; WALL_NUM <= 0 ==> goto ALL_DIR_CONV_DONE
; else here WALL_NUM > 0
6FD76670 |. 8D43 1C LEA EAX,DWORD PTR DS:[EBX+1C] ; EAX = adress of OFF_DIR_1 6FD76673 |. 894424 2C MOV DWORD PTR SS:[ESP+2C],EAX ; CUR_DIR_OFF = adress of OFF_DIR_1
LOOP_CONV_DIR : =============== 6FD76677 |> 8B4C24 2C /MOV ECX,DWORD PTR SS:[ESP+2C] ; ECX = adress of OFF_DIR_x in INFO 6FD7667B |. 85ED |TEST EBP,EBP ; # of Tiles in 1 layer positive ? 6FD7667D |. 8B39 |MOV EDI,DWORD PTR DS:[ECX] ; move pointer to value in OFF_DIR_X ; = move pointer to start of 1 direction layer 6FD7667F |. 7E 17 |JLE SHORT D2Common.6FD76698 ; # of Tiles in 1 layer <= 0 ==> goto DIR_CONV_DONE
; else here # of Tiles in 1 layer > 0
6FD76681 |. 8B6C24 1C |MOV EBP,DWORD PTR SS:[ESP+1C] ; EBP = # of Tiles in 1 layer ; = # of Direction value to process
6FD76685 |> 8B0F |/MOV ECX,DWORD PTR DS:[EDI] ; ECX = current Direction Tile 6FD76687 |. E8 342B0000 ||CALL D2Common.6FD791C0 ;
CODE OF D2Common.6FD791C0 (1.09b) : =================================== 6FD791C0 /$ 8B048D 58FCDB6F MOV EAX,DWORD PTR DS:[ECX*4+6FDBFC58] ; EAX = 1 dword from this lookup table 6FD791C7 \. C3 RETN
LOOKUP TABLE AT 6FDBFC58 (all dwords, at least 25 elements) : ============================================================= 0, 1, 2, 1, 2, 3, 3, 5, 5, 6, 6, 7, 7, 8, 9, A, B, C, D, E, F, 10, 11, 12, 14 <-- lookup values (but since I don't know its real size, I'll stop here, as after it start again from 0)
Note that there's no higher direction in all the ds1 than 19, so this lookup table may have only 19 elements ?
6FD7668C |. 8907 ||MOV DWORD PTR DS:[EDI],EAX ; current Direction Tile = value from lookup table
6FD7668E |. 83C7 04 ||ADD EDI,4 ; move pointer to next Direction Tile 6FD76691 |. 4D ||DEC EBP ; EBP -- (1 less Direction Tile to process) 6FD76692 |.^75 F1 |\JNZ SHORT D2Common.6FD76685 ; EBP <> 0 ==> loop (read next Direction values)
6FD76694 |. 8B6C24 1C |MOV EBP,DWORD PTR SS:[ESP+1C] ; EBP = # of Tiles in 1 layer
DIR_CONV_DONE : =============== 6FD76698 |> 8B4424 18 |MOV EAX,DWORD PTR SS:[ESP+18] ; 6FD7669C |. 8B5424 2C |MOV EDX,DWORD PTR SS:[ESP+2C] ; EDX = CUR_DIR_OFF 6FD766A0 |. 8B4B 14 |MOV ECX,DWORD PTR DS:[EBX+14] ; ECX = WALL_NUM 6FD766A3 |. 40 |INC EAX ; DIR_READ ++ 6FD766A4 |. 83C2 04 |ADD EDX,4 ; EDX = next Direction Offset data 6FD766A7 |. 3BC1 |CMP EAX,ECX ; DIR_READ = WALL_NUM ? 6FD766A9 |. 894424 18 |MOV DWORD PTR SS:[ESP+18],EAX ; 6FD766AD |. 895424 2C |MOV DWORD PTR SS:[ESP+2C],EDX ; CUR_DIR_OFF = next Direction Offset data 6FD766B1 |.^7C C4 \JL SHORT D2Common.6FD76677 ; DIR_READ < WALL_NUM ==> LOOP_CONV_DIR ; (will convert next Direction layer)
6FD766B3 |. 8B7C24 14 MOV EDI,DWORD PTR SS:[ESP+14] ; EDI = VERSION
ALL_DIR_CONV_DONE : ===================
========================================================================================================== now we're on the Shadow layer ==========================================================================================================
6FD766B7 |> 8B0B MOV ECX,DWORD PTR DS:[EBX] ; ECX = UNK_TYPE 6FD766B9 |. 8D04AD 00000000 LEA EAX,DWORD PTR DS:[EBP*4] ; EAX = # of * BYTES * in 1 layer 6FD766C0 |. 8973 44 MOV DWORD PTR DS:[EBX+44],ESI ; put current address in OFF_SHAD 6FD766C3 |. 03F0 ADD ESI,EAX ; skip this SHADOW layer
========================================================================================================== handle of Unknown layer (only present if UNK_TYPE = 1 or 2) ==========================================================================================================
6FD766C5 |. 85C9 TEST ECX,ECX ; UNK_TYPE = 0 ? 6FD766C7 |. BD 02000000 MOV EBP,2 ; EBP = 2 6FD766CC |. 7E 09 JLE SHORT D2Common.6FD766D7 ; UNK_TYPE <= 0 ==> goto UNK_LAY_DONE
; else here UNK_TYPE > 0
6FD766CE |. 3BCD CMP ECX,EBP ; UNK_TYPE = 2 ? 6FD766D0 |. 7F 05 JG SHORT D2Common.6FD766D7 ; UNK_TYPE > 2 ==> goto UNK_LAY_DONE
; else here UNK_TYPE is 1 or 2
6FD766D2 |. 8973 48 MOV DWORD PTR DS:[EBX+48],ESI ; put current address in OFF_UNK 6FD766D5 |. 03F0 ADD ESI,EAX ; skip this UNKNOWN layer
UNK_LAY_DONE : ==============
_________________ DT1 Tools - DS1 Editor - MPQ list file - Extracting D2 Animation tutorial
"Sorry I can't give you offsets or anything, my dlls are always very mutant compared to what's in the release" - Isolde, aka Peter Hu, 30 Jun 2002
Last edited by Paul Siramy on Fri Nov 22, 2002 8:10 am, edited 1 time in total.
|
|
| Top |
|
 |
|
Paul Siramy
|
Posted: Fri Nov 22, 2002 3:35 am Post subject: |
|
Age: 35 Joined: Sat May 25, 2002 2:39 pm Posts: 2738 Location: La Garenne Colombes (near Paris) Gender:
|
OBJECTS :
We'll handle objects of Type 1, 2 and 4. In fact, there's no objects of type 4 in all the 2264 ds1 I have checked, so you can skip the complex part of the Type 4 objects.
Apparently, a ds1 can use the Type 2 objects of the previous acts (no check), but it can't use the ones of the further acts (there IS this check). By just removing this check any ds1 should be able to use any objects of Type 2 (like for Type 1 currently).
================================================================================ now we're on the object datas (infos presents only since VERSION 2) ================================================================================
6FD766D7 |> 83FF 01 CMP EDI,1 ; VERSION = 1 ? 6FD766DA |. 0F8E 33020000 JLE D2Common.6FD76913 ; VERSION <= 1 ==> goto END_OBJECTS 6FD766E0 |. 8B06 MOV EAX,DWORD PTR DS:[ESI] ; EAX = OBJ_NUM 6FD766E2 |. 83C6 04 ADD ESI,4 ; move pointer to next data 6FD766E5 |. 85C0 TEST EAX,EAX ; OBJ_NUM positive ?
6FD766E7 |. 0F84 26020000 JE D2Common.6FD76913 ; OBJ_NUM = 0 ==> goto END_OBJECTS ; from SVR : not needed, great compiler ;)
6FD766ED |. 0F8E 20020000 JLE D2Common.6FD76913 ; OBJ_NUM <= 0 ==> goto END_OBJECTS 6FD766F3 |. 894424 24 MOV DWORD PTR SS:[ESP+24],EAX ; save OBJ_NUM
READ_OBJECT : ============= 6FD766F7 |> 8B0E /MOV ECX,DWORD PTR DS:[ESI] ; ECX = TYPE 6FD766F9 |. 8B46 04 |MOV EAX,DWORD PTR DS:[ESI+4] ; EAX = ID 6FD766FC |. 8B5424 20 |MOV EDX,DWORD PTR SS:[ESP+20] ; EDX = ACT 6FD76700 |. 83C6 04 |ADD ESI,4 ; move pointer to ID 6FD76703 |. 894C24 1C |MOV DWORD PTR SS:[ESP+1C],ECX ; save TYPE 6FD76707 |. 83C6 04 |ADD ESI,4 ; move pointer to X 6FD7670A |. 33FF |XOR EDI,EDI ; EDI = 0
switch (type), case 1, 2, 4 default
6FD7670C |. 49 |DEC ECX ; TYPE -- 6FD7670D |. 894424 2C |MOV DWORD PTR SS:[ESP+2C],EAX ; NEW_ID = ID 6FD76711 |. 897C24 10 |MOV DWORD PTR SS:[ESP+10],EDI ; (dword) CODE = 0 6FD76715 |. 0F84 F3000000 |JE D2Common.6FD7680E ; TYPE = 0 ==> was 1 ==> goto TYPE_IS_1 6FD7671B |. 49 |DEC ECX ; TYPE -- 6FD7671C |. 0F84 B3000000 |JE D2Common.6FD767D5 ; TYPE = 0 ==> was 2 ==> goto TYPE_IS_2 6FD76722 |. 2BCD |SUB ECX,EBP ; TYPE = TYPE - 2
6FD76724 |. 0F85 85010000 |JNZ D2Common.6FD768AF ; TYPE <> 0 ==> wasn't 4 ==> goto END_READ_OBJ
TYPE_IS_4 : =========== 6FD7672A |. 837C24 14 04 |CMP DWORD PTR SS:[ESP+14],4 ; VERSION = 4 ? 6FD7672F |. 0F8E 93000000 |JLE D2Common.6FD767C8 ; VERSION <= 4 ==> goto VERSION_<_5
; else here VERSION >= 5
6FD76735 |. 8B1485 E446DD6F |MOV EDX,DWORD PTR DS:[EAX*4+6FDD46E4]; Lookup table for Item code ( with ID ) ; (LookUp is now an offset)
6FD7673C |. 6A 04 |PUSH 4 ; PUSH 4 6FD7673E |. 8D4424 1C |LEA EAX,DWORD PTR SS:[ESP+1C] ; EAX = address of TYPE 6FD76742 |. 52 |PUSH EDX ; PUSH Lookup table for Item code ( with ID ) 6FD76743 |. 50 |PUSH EAX ; PUSH address of TYPE 6FD76744 |. E8 27DD0300 |CALL D2Common.6FDB4470 ; copy_string( & TYPE, LookUp, 4);
=========================================================================================== CODE OF D2Common.6FDB4470 : copy_string(BYTE * PTR_DEST, BYTE * PTR_SRC, DWORD BYTE_NUM) =========================================================================================== In our case this function copy a string of at most 4 characters from LookUp (wich is an offset) to TYPE.
This function is something like STRNCPY(), but it also fill the end of the DEST string with zero. Apparently, there's some kind of optimization, as it check if PTR_SRC and PTR_END are on a DWORD boundary, for copying AND filling zero. Hence this mess. I don't know if it's optimization or not (I doubt it), but there's something special about copying dwords, see at the COPY_DWORDS label.
6FDB4470 /$ 8B4C24 0C MOV ECX,DWORD PTR SS:[ESP+C] ; ECX = BYTE_NUM 6FDB4474 |. 57 PUSH EDI ; save EDI 6FDB4475 |. 85C9 TEST ECX,ECX ; BYTE_NUM positive ? 6FDB4477 |. 74 7A JE SHORT D2Common.6FDB44F3 ; BYTE_NUM = 0 ==> goto END_COPY_BYTES
; else here BYTE_NUM > 0
6FDB4479 |. 56 PUSH ESI ; save ESI 6FDB447A |. 53 PUSH EBX ; save EBX 6FDB447B |. 8BD9 MOV EBX,ECX ; EBX = BYTE_NUM 6FDB447D |. 8B7424 14 MOV ESI,DWORD PTR SS:[ESP+14] ; ESI = PTR_SCR 6FDB4481 |. F7C6 03000000 TEST ESI,3 ; PTR_SRC AND 3 6FDB4487 |. 8B7C24 10 MOV EDI,DWORD PTR SS:[ESP+10] ; EDI = (dword) CODE 6FDB448B |. 75 07 JNZ SHORT D2Common.6FDB4494 ; (PTR_SRC AND 3) <> 0 ==> goto LOOP_SRC_NOT_OK
; else here PTR_SRC is on a DWORD boundary
6FDB448D |. C1E9 02 SHR ECX,2 ; ECX = DWORD_NUM = BYTE_NUM / 4 ; ( = # of dwords to process)
6FDB4490 |. 75 6F JNZ SHORT D2Common.6FDB4501 ; DWORD_NUM <> 0 ==> goto COPY_DWORDS
; else here DWORD_NUM = 0
6FDB4492 |. EB 21 JMP SHORT D2Common.6FDB44B5 ; goto COPY_ENDING_BYTES ; ( to process some eventual BYTE_NUM % 4)
LOOP_SRC_NOT_OK : (ECX = EBX = BYTE_NUM) ================= 6FDB4494 |> 8A06 /MOV AL,BYTE PTR DS:[ESI] ; AL = * PTR_SRC 6FDB4496 |. 46 |INC ESI ; PTR_SRC++ 6FDB4497 |. 8807 |MOV BYTE PTR DS:[EDI],AL ; * PTR_DEST = AL 6FDB4499 |. 47 |INC EDI ; PTR_DEST++ 6FDB449A |. 49 |DEC ECX ; BYTE_NUM-- 6FDB449B |. 74 25 |JE SHORT D2Common.6FDB44C2 ; BYTE_NUM = 0 ==> goto END_SRC_NOT_OK
; else here BYTE_NUM <> 0
6FDB449D |. 84C0 |TEST AL,AL ; AL positive ? 6FDB449F |. 74 29 |JE SHORT D2Common.6FDB44CA ; AL = 0 ==> goto ENDING_FILL_ZERO 6FDB44A1 |. F7C6 03000000 |TEST ESI,3 ; PTR_SCR AND 3 6FDB44A7 |.^75 EB \JNZ SHORT D2Common.6FDB4494 ; (PTR_SCR AND 3) <> 0 ==> goto LOOP_SRC_NOT_OK
; else now PTR_SRC is on a DWORD boundary
6FDB44A9 |. 8BD9 MOV EBX,ECX ; EBX = BYTE_NUM 6FDB44AB |. C1E9 02 SHR ECX,2 ; ECX = DWORD_NUM = BYTE_NUM / 4 6FDB44AE |. 75 51 JNZ SHORT D2Common.6FDB4501 ; DWORD_NUM <> 0 ==> goto COPY_DWORDS
END_COPY_DWORD : test if BYTE_NUM % 4 bytes to process ================ 6FDB44B0 |> 83E3 03 AND EBX,3 ; EBX = BYTE_NUM AND 3 6FDB44B3 |. 74 0D JE SHORT D2Common.6FDB44C2 ; EBX = 0 ==> goto END_SRC_NOT_OK
COPY_ENDING_BYTES : (ECX = DWORD_NUM) =================== 6FDB44B5 |> 8A06 /MOV AL,BYTE PTR DS:[ESI] ; AL = * PTR_SRC 6FDB44B7 |. 46 |INC ESI ; PTR_SRC++ 6FDB44B8 |. 8807 |MOV BYTE PTR DS:[EDI],AL ; * PTR_DEST = AL 6FDB44BA |. 47 |INC EDI ; PTR_DEST++ 6FDB44BB |. 84C0 |TEST AL,AL ; AL positive ? 6FDB44BD |. 74 2F |JE SHORT D2Common.6FDB44EE ; AL = 0 ==> goto END_OF_STRING 6FDB44BF |. 4B |DEC EBX ; BYTE_NUM-- 6FDB44C0 |.^75 F3 \JNZ SHORT D2Common.6FDB44B5 : BYTE_NUM <> 0 ==> goto COPY_ENDING_BYTES
END_SRC_NOT_OK : ================ 6FDB44C2 |> 8B4424 10 MOV EAX,DWORD PTR SS:[ESP+10] ; EAX = PTR_DEST 6FDB44C6 |. 5B POP EBX ; restore EBX 6FDB44C7 |. 5E POP ESI ; restore ESI 6FDB44C8 |. 5F POP EDI ; restore EDI 6FDB44C9 |. C3 RETN ; RETURN ==> return PTR_DEST;
ENDING_FILL_ZERO : (AL = 0, but BYTE_NUM NOT zero, so fill the end of the PTR_DEST data with zero) (ECX = EBX = BYTE_NUM) ================== 6FDB44CA |> F7C7 03000000 TEST EDI,3 ; PTR_DEST AND 3 6FDB44D0 |. 74 12 JE SHORT D2Common.6FDB44E4 ; (PTR_DEST AND 3) = 0 ==> goto ENDING_ON_DWORD
; else here PTR_DEST is NOT on a dword boundary DEST_NOT_DWORD : ================ 6FDB44D2 |> 8807 /MOV BYTE PTR DS:[EDI],AL ; * PTR_DEST = AL ( = 0 in fact) 6FDB44D4 |. 47 |INC EDI ; PTR_DEST++ 6FDB44D5 |. 49 |DEC ECX ; BYTE_NUM-- 6FDB44D6 |. 0F84 8A000000 |JE D2Common.6FDB4566 ; BYTE_NUM = 0 ==> goto ENDING 6FDB44DC |. F7C7 03000000 |TEST EDI,3 ; PTR_DEST AND 3 6FDB44E2 |.^75 EE \JNZ SHORT D2Common.6FDB44D2 ; (PTR_DEST AND 3) <> 0 ==> goto DEST_NOT_DWORD
; else here DEST is on a DWORD boundary ENDING_ON_DWORD : ================= 6FDB44E4 |> 8BD9 MOV EBX,ECX ; EBX = BYTE_NUM 6FDB44E6 |. C1E9 02 SHR ECX,2 ; ECX = DWORD_NUM = BYTE_NUM / 4 6FDB44E9 |. 75 6C JNZ SHORT D2Common.6FDB4557 ; DWORD_NUM <> 0 ==> goto ENDING_ON_DWORD_2
LOOP_END_OF_STRING : ==================== 6FDB44EB |> 8807 MOV BYTE PTR DS:[EDI],AL ; * PTR_DEST = 0 6FDB44ED |. 47 INC EDI ; PTR_DEST++
END_OF_STRING : (AL = 0) =============== 6FDB44EE |> 4B DEC EBX ; BYTE_NUM-- 6FDB44EF |.^75 FA JNZ SHORT D2Common.6FDB44EB ; BYTE_NUM <> 0 ==> goto LOOP_END_OF_STRING 6FDB44F1 |. 5B POP EBX ; restore EBX 6FDB44F2 |. 5E POP ESI ; restore ESI
END_COPY_BYTES : ================ 6FDB44F3 |> 8B4424 08 MOV EAX,DWORD PTR SS:[ESP+8] ; EAX = PTR_DEST 6FDB44F7 |. 5F POP EDI ; restore EDI 6FDB44F8 |. C3 RETN ; RETURN ==> return PTR_DEST;
START_COPY_DWORDS : =================== 6FDB44F9 |> 8917 /MOV DWORD PTR DS:[EDI],EDX ; on dword : * PTR_DEST = * PTR_SRC 6FDB44FB |. 83C7 04 |ADD EDI,4 ; PTR_DEST on next dword 6FDB44FE |. 49 |DEC ECX ; DWORD_NUM-- 6FDB44FF |.^74 AF |JE SHORT D2Common.6FDB44B0 ; DWORD_NUM = 0 ==> goto END_COPY_DWORD
COPY_DWORDS : (EBX = BYTE_NUM, ECX = DWORD_NUM) =============
We want to copy a dword from PTR_SRC to PTR_DEST (a string of at most 4 characters from SRC to DEST), then if
((* PTR_SRC) XOR (FFFFFFFF) XOR (7EFEFEFF + (* PTR_SRC))) AND 81010100 = 0 ==> we copy it,
(I think this means that if NONE of the bytes of this dword are set to zero, then no termination string at all, so we simply copy the 4 character of the string... but it's just a guess, in fact I don't understand).
else we analyse at most 4 bytes of the PTR_SRC dword to know what to copy :
if ((* PTR_SRC & 0x000000FF) == 0) * PTR_DEST = 0; else if ((* PTR_SRC & 0x0000FF00) == 0) * PTR_DEST = * PTR_SRC & 0x000000FF; else if ((* PTR_SRC & 0x00FF0000) == 0) * PTR_DEST = * PTR_SRC & 0x0000FFFF; else if ((* PTR_SRC & 0xFF000000) == 0) * PTR_DEST = * PTR_SRC; // it's correct in this case
(in other words, we copy what is before a termination zero of a string, and meanwhile we fill the other bytes to 0)
6FDB4501 |> BA FFFEFE7E MOV EDX,7EFEFEFF ; EDX = 0x7EFEFEFF ; = 0111-1110 1111-1110 1111-1110 1111-1111 6FDB4506 |. 8B06 |MOV EAX,DWORD PTR DS:[ESI] ; EAX = * ((DWORD *) PTR_SRC) 6FDB4508 |. 03D0 |ADD EDX,EAX ; EDX = EDX + * ((DWORD *) PTR_SRC) 6FDB450A |. 83F0 FF |XOR EAX,FFFFFFFF ; 6FDB450D |. 33C2 |XOR EAX,EDX ; 6FDB450F |. 8B16 |MOV EDX,DWORD PTR DS:[ESI] ; EDX = * ((DWORD *) PTR_SRC) 6FDB4511 |. 83C6 04 |ADD ESI,4 ; PTR_SRC on next dword 6FDB4514 |. A9 00010181 |TEST EAX,81010100 ; EAX = EAX AND 0x81010100 ; AND 1000-0001 0000-0001 0000-0001 0000-0000 6FDB4519 |.^74 DE |JE SHORT D2Common.6FDB44F9 ; EAX = 0 ==> goto START_COPY_DWORDS
6FDB451B |. 84D2 |TEST DL,DL ; * PTR_SRC AND 0x000000FF ? 6FDB451D |. 74 2C |JE SHORT D2Common.6FDB454B ; zero ==> goto BYTE_0 6FDB451F |. 84F6 |TEST DH,DH ; * PTR_SRC AND 0x0000FF00 ? 6FDB4521 |. 74 1E |JE SHORT D2Common.6FDB4541 ; zero ==> goto BYTE_1 6FDB4523 |. F7C2 0000FF00 |TEST EDX,0FF0000 ; * PTR_SRC AND 0x00FF0000 ? 6FDB4529 |. 74 0C |JE SHORT D2Common.6FDB4537 ; zero ==> goto BYTE_2 6FDB452B |. F7C2 000000FF |TEST EDX,FF000000 ; * PTR_SRC AND 0xFF000000 ? 6FDB4531 |.^75 C6 \JNZ SHORT D2Common.6FDB44F9 ; something ==> goto START_COPY_DWORDS 6FDB4533 |. 8917 MOV DWORD PTR DS:[EDI],EDX ; * PTR_DEST = * PTR_SRC 6FDB4535 |. EB 18 JMP SHORT D2Common.6FDB454F ; goto AFTER_BYTES_N
BYTE_2 : ======== 6FDB4537 |> 81E2 FFFF0000 AND EDX,0FFFF ; EDX = * PTR_SRC & 0x0000FFFF 6FDB453D |. 8917 MOV DWORD PTR DS:[EDI],EDX ; * PTR_DEST = * PTR_SRC & 0x0000FFFF 6FDB453F |. EB 0E JMP SHORT D2Common.6FDB454F ; goto AFTER_BYTES_N
BYTE_1 : ======== 6FDB4541 |> 81E2 FF000000 AND EDX,0FF ; EDX = * PTR_SRC AND 0x000000FF 6FDB4547 |. 8917 MOV DWORD PTR DS:[EDI],EDX ; * PTR_DEST = * PTR_SRC AND 0xFF 6FDB4549 |. EB 04 JMP SHORT D2Common.6FDB454F ; goto AFTER_BYTES_N
BYTE_0 : ======== 6FDB454B |> 33D2 XOR EDX,EDX ; EDX = 0 6FDB454D |. 8917 MOV DWORD PTR DS:[EDI],EDX ; * PTR_DEST = 0
AFTER_BYTES_N : =============== 6FDB454F |> 83C7 04 ADD EDI,4 ; PTR_DEST on next dword 6FDB4552 |. 33C0 XOR EAX,EAX ; EAX = 0 6FDB4554 |. 49 DEC ECX ; DWORD_NUM-- 6FDB4555 |. 74 0A JE SHORT D2Common.6FDB4561 ; DWORD_NUM = 0 ==> goto ENDING_ON_DWORD_3
ENDING_ON_DWORD_2 : (EBX = BYTE_NUM, ECX = DWORD_NUM) =================== we fill explicitly all final dwords to 0
6FDB4557 |> 33C0 XOR EAX,EAX ; EAX = 0
6FDB4559 |> 8907 /MOV DWORD PTR DS:[EDI],EAX ; * PTR_DEST = 0 6FDB455B |. 83C7 04 |ADD EDI,4 ; PTR_DEST on next dword 6FDB455E |. 49 |DEC ECX ; DWORD_NUM-- 6FDB455F |.^75 F8 \JNZ SHORT D2Common.6FDB4559 ; DWORD_NUM <> 0 ==> loop
ENDING_ON_DWORD_3 : (EBX = BYTE_NUM, ECX = DWORD_NUM) (EAX = 0) =================== 6FDB4561 |> 83E3 03 AND EBX,3 ; BYTE_NUM AND 3 6FDB4564 |.^75 85 JNZ SHORT D2Common.6FDB44EB ; <> 0 ==> goto LOOP_END_OF_STRING
ENDING : ========
6FDB4566 |> 8B4424 10 MOV EAX,DWORD PTR SS:[ESP+10] ; EAX = PTR_DEST 6FDB456A |. 5B POP EBX ; restore EBX 6FDB456B |. 5E POP ESI ; restore ESI 6FDB456C |. 5F POP EDI ; restore EDI 6FDB456D \. C3 RETN ; RETURN ==> return PTR_DEST;
============================================================================================================= continuation of the objects type stuff, still in the case of object with Type 4 =============================================================================================================
6FD76749 |. 83C4 0C |ADD ESP,0C ; POP stack back
Here, if VERSION < 7, DIR_READ = WALL_NUM, else undefined (0 ?)
6FD7674C |. C64424 1B 00 |MOV BYTE PTR SS:[ESP+1B],0 ; DIR_READ &= 0x00FFFFFF
; EDI is currently = 0 ==> I = 0
we'll process each 3 bytes (the non-zero ones) of DIR_READ
6FD76751 |> 0FBE4C3C 18 |/MOVSX ECX,BYTE PTR SS:[ESP+EDI+18] ; ECX = DIR_READ [I]; 6FD76756 |. 51 ||PUSH ECX ; PUSH this byte 6FD76757 |. E8 D0DB0300 ||CALL D2Common.6FDB432C ; EAX = to_lower(this byte) ; (in 1 case something else, too complex for me)
6FD7675C |. 83C4 04 ||ADD ESP,4 ; POP stack back 6FD7675F |. 88443C 18 ||MOV BYTE PTR SS:[ESP+EDI+18],AL ; DIR_READ [I] = AL 6FD76763 |. 47 ||INC EDI ; I++ 6FD76764 |. 83FF 03 ||CMP EDI,3 ; I = 3 ? 6FD76767 |.^7C E8 |\JL SHORT D2Common.6FD76751 ; I < 3 ==> loop
now just replace null code bytes with space
6FD76769 |. 8A4424 18 |MOV AL,BYTE PTR SS:[ESP+18] ; AL = DIR_READ [0] = WALL_NUM if VERSION was < 7 6FD7676D |. C74424 10 00000000 |MOV DWORD PTR SS:[ESP+10],0 ; (dword) CODE = 0 6FD76775 |. 84C0 |TEST AL,AL ; AL positive ? 6FD76777 |. 884424 10 |MOV BYTE PTR SS:[ESP+10],AL ; CODE [0] = AL 6FD7677B |. 75 05 |JNZ SHORT D2Common.6FD76782 ; AL <> 0 ==> goto SKIP_0 6FD7677D |. C64424 10 20 |MOV BYTE PTR SS:[ESP+10],20 ; CODE [0] = ' ' (space)
SKIP_0 : ======== 6FD76782 |> 8A4424 19 |MOV AL,BYTE PTR SS:[ESP+19] ; AL = DIR_READ[1] 6FD76786 |. 84C0 |TEST AL,AL ; AL positive ? 6FD76788 |. 884424 11 |MOV BYTE PTR SS:[ESP+11],AL ; CODE [1] = AL 6FD7678C |. 75 05 |JNZ SHORT D2Common.6FD76793 ; AL <> 0 ==> goto SKIP_1 6FD7678E |. C64424 11 20 |MOV BYTE PTR SS:[ESP+11],20 ; CODE [1] = ' ' (space)
SKIP_1 : ======== 6FD76793 |> 8A4424 1A |MOV AL,BYTE PTR SS:[ESP+1A] 6FD76797 |. 84C0 |TEST AL,AL 6FD76799 |. 884424 12 |MOV BYTE PTR SS:[ESP+12],AL ; CODE [2] = AL 6FD7679D |. 75 05 |JNZ SHORT D2Common.6FD767A4 6FD7679F |. C64424 12 20 |MOV BYTE PTR SS:[ESP+12],20 ; CODE [2] = ' ' (space) 6FD767A4 |> 8A4424 1B |MOV AL,BYTE PTR SS:[ESP+1B] 6FD767A8 |. 84C0 |TEST AL,AL 6FD767AA |. 884424 13 |MOV BYTE PTR SS:[ESP+13],AL ; CODE [3] = AL 6FD767AE |. 75 05 |JNZ SHORT D2Common.6FD767B5 6FD767B0 |. C64424 13 20 |MOV BYTE PTR SS:[ESP+13],20 ; CODE [3] = ' ' (space) 6FD767B5 |> 8B4424 10 |MOV EAX,DWORD PTR SS:[ESP+10] 6FD767B9 |. 8D5424 2C |LEA EDX,DWORD PTR SS:[ESP+2C] ; EDX = NEW_ID 6FD767BD |. 52 |PUSH EDX 6FD767BE |. 50 |PUSH EAX 6FD767BF |. E8 4C86FDFF |CALL D2Common.#10601 6FD767C4 |. 8B4424 2C |MOV EAX,DWORD PTR SS:[ESP+2C] ; EAX = NEW_ID
VERSION_<_5 : (in case 4) ============= 6FD767C8 |> C74424 10 03000000 |MOV DWORD PTR SS:[ESP+10],3 ; (dword) CODE = 3 6FD767D0 |. E9 DA000000 |JMP D2Common.6FD768AF ; ==> goto END_READ_OBJ
TYPE_IS_2 : ===========
Now, for both Type 2 and Type 1 objects, we'll make some modifications, eventually. Don't forget that the ACT value range from 0 to 4, so the "ACT = 2 ?" check means in fact "ACT = 3 ?" for us.
6FD767D5 |> 3D 3D020000 |CMP EAX,23D ; ID = 573 ? 6FD767DA |. 0F84 C8000000 |JE D2Common.6FD768A8 ; ID = 573 ==> goto SET_BAD_ID
; else here ID <> 573
6FD767E0 |. 837C24 14 05 |CMP DWORD PTR SS:[ESP+14],5 ; VERSION = 5 ? 6FD767E5 |. 0F8E C4000000 |JLE D2Common.6FD768AF ; VERSION <= 5 ==> goto END_READ_OBJ 6FD767EB |. 3D 96000000 |CMP EAX,96 ; ID = 150 ? 6FD767F0 |. 0F8D B2000000 |JGE D2Common.6FD768A8 ; ID >= 150 ==> goto SET_BAD_ID
; else here ID < 150
6FD767F6 |. 8D0C52 |LEA ECX,DWORD PTR DS:[EDX+EDX*2] ; ECX = ACT * 3 6FD767F9 |. 8D0C89 |LEA ECX,DWORD PTR DS:[ECX+ECX*4] ; ECX = ACT * 15 6FD767FC |. 8D0C89 |LEA ECX,DWORD PTR DS:[ECX+ECX*4] ; ECX = ACT * 75 6FD767FF |. 8D1448 |LEA EDX,DWORD PTR DS:[EAX+ECX*2] ; EDX = ID + ACT * 150 6FD76802 |. 8B0495 7C36DD6F |MOV EAX,DWORD PTR DS:[EDX*4+6FDD367C]; ID = Lookup table for Type 2 objects 6FD76809 |. E9 9D000000 |JMP D2Common.6FD768AB ; ==> goto CHANGE_ID
TYPE_IS_1 : =========== 6FD7680E |> 837C24 14 04 |CMP DWORD PTR SS:[ESP+14],4 ; VERSION = 4 ? 6FD76813 |. 0F8E 80000000 |JLE D2Common.6FD76899 ; VERSION <= 4 ==> goto TYPE1_VER_<_5
; else here VERSION > 4
6FD76819 |. 8D0C52 |LEA ECX,DWORD PTR DS:[EDX+EDX*2] ; ECX = ACT * 3 6FD7681C |. 3BD5 |CMP EDX,EBP ; ACT = 2 ? 6FD7681E |. 8D0C89 |LEA ECX,DWORD PTR DS:[ECX+ECX*4] ; ECX = ACT * 15 6FD76821 |. 8D0488 |LEA EAX,DWORD PTR DS:[EAX+ECX*4] ; ID = ID + ACT * 60 6FD76824 |. 8B0485 3442DD6F |MOV EAX,DWORD PTR DS:[EAX*4+6FDD4234]; ID = Lookup table for Type 1 objects 6FD7682B |. 894424 2C |MOV DWORD PTR SS:[ESP+2C],EAX ; NEW_ID = ID 6FD7682F |. 75 2C |JNZ SHORT D2Common.6FD7685D ; ACT <> 2 ==> goto TYPE1_ACT_NOT_2
; else here ACT = 2 (act 3 for us)
6FD76831 |. 3D 29010000 |CMP EAX,129 ; ID = 297 ? 6FD76836 |. 75 0F |JNZ SHORT D2Common.6FD76847 ; ID <> 297 ==> goto TYPE1_ACT2_ID_NOT_297
; else here ID = 297
6FD76838 |. B8 7E010000 |MOV EAX,17E ; ID = 382 6FD7683D |. 896C24 1C |MOV DWORD PTR SS:[ESP+1C],EBP ; TYPE = 2 6FD76841 |. 894424 2C |MOV DWORD PTR SS:[ESP+2C],EAX ; NEW_ID = 382 6FD76845 |. EB 68 |JMP SHORT D2Common.6FD768AF ; ==> goto END_READ_OBJ
TYPE1_ACT2_ID_NOT_297 : ======================= 6FD76847 |> 3D 6E010000 |CMP EAX,16E ; ID = 366 ? 6FD7684C |. 75 4B |JNZ SHORT D2Common.6FD76899 ; ID <> 366 ==> goto TYPE1_VER_<_5 6FD7684E |. B8 94010000 |MOV EAX,194 ; ID = 404 6FD76853 |. 896C24 1C |MOV DWORD PTR SS:[ESP+1C],EBP ; TYPE = 2 6FD76857 |. 894424 2C |MOV DWORD PTR SS:[ESP+2C],EAX ; NEW_ID = 404 6FD7685B |. EB 52 |JMP SHORT D2Common.6FD768AF ; ==> goto END_READ_OBJ
TYPE1_ACT_NOT_2 : ================= 6FD7685D |> 83FA 04 |CMP EDX,4 ; ACT = 4 ? (act 5 for us) 6FD76860 |. 75 37 |JNZ SHORT D2Common.6FD76899 ; ACT <> 4 ==> goto TYPE1_VER_<_5 6FD76862 |. 3D 19020000 |CMP EAX,219 ; ID = 537 ? 6FD76867 |. 7C 1A |JL SHORT D2Common.6FD76883 ; ID < 537 ==> goto TYPE1_ACT4_ID_NOT_53X 6FD76869 |. 3D 1B020000 |CMP EAX,21B ; ID = 539 ? 6FD7686E |. 7F 13 |JG SHORT D2Common.6FD76883 ; ID > 539 ==> goto TYPE1_ACT4_ID_NOT_53X 6FD76870 |. B9 F5030000 |MOV ECX,3F5 ; ECX = 1013 6FD76875 |. 896C24 1C |MOV DWORD PTR SS:[ESP+1C],EBP ; TYPE = 2 6FD76879 |. 2BC8 |SUB ECX,EAX ; 6FD7687B |. 8BC1 |MOV EAX,ECX ; ID = 1013 - ID 6FD7687D |. 894424 2C |MOV DWORD PTR SS:[ESP+2C],EAX ; NEW_ID = ID 6FD76881 |. EB 2C |JMP SHORT D2Common.6FD768AF ; ==> goto END_READ_OBJ
TYPE1_ACT4_ID_NOT_53X : ======================= 6FD76883 |> 3D 02020000 |CMP EAX,202 ; ID = 514 ? 6FD76888 |. 75 0F |JNZ SHORT D2Common.6FD76899 ; ID <> 514 ==> goto TYPE1_VER_<_5 6FD7688A |. B8 CD010000 |MOV EAX,1CD ; ID = 461 6FD7688F |. 896C24 1C |MOV DWORD PTR SS:[ESP+1C],EBP ; TYPE = 2 6FD76893 |. 894424 2C |MOV DWORD PTR SS:[ESP+2C],EAX ; NEW_ID = 461 6FD76897 |. EB 16 |JMP SHORT D2Common.6FD768AF ; ==> goto END_READ_OBJ
TYPE1_VER_<_5 : =============== 6FD76899 |> 3D 3F020000 |CMP EAX,23F ; ID = 575 ? 6FD7689E |. C74424 10 01000000 |MOV DWORD PTR SS:[ESP+10],1 ; (dword) CODE = 1 6FD768A6 |. 75 07 |JNZ SHORT D2Common.6FD768AF ; ID <> 575 ==> goto END_READ_OBJ
SET_BAD_ID : ============ 6FD768A8 |> 83C8 FF |OR EAX,FFFFFFFF ; ID = -1
CHANGE_ID : =========== 6FD768AB |> 894424 2C |MOV DWORD PTR SS:[ESP+2C],EAX ; NEW_ID = ID
END_READ_OBJ : ============== 6FD768AF |> 8B0E |MOV ECX,DWORD PTR DS:[ESI] ; ECX = X 6FD768B1 |. 8B56 04 |MOV EDX,DWORD PTR DS:[ESI+4] ; EDX = Y 6FD768B4 |. 8B6C24 14 |MOV EBP,DWORD PTR SS:[ESP+14] ; EBP = VERSION 6FD768B8 |. 83C6 04 |ADD ESI,4 ; move pointer to Y 6FD768BB |. 83C6 04 |ADD ESI,4 ; move pointer to next data 6FD768BE |. 33FF |XOR EDI,EDI ; EDI = 0 6FD768C0 |. 83FD 05 |CMP EBP,5 ; VERSION = 5 ? 6FD768C3 |. 7E 05 |JLE SHORT D2Common.6FD768CA ; VERSION <= 5 ==> goto FLAGS_DONE
; else here VERSION > 5
6FD768C5 |. 8B3E |MOV EDI,DWORD PTR DS:[ESI] ; EDI = FLAGS 6FD768C7 |. 83C6 04 |ADD ESI,4 ; move pointer to next data
FLAGS_DONE : ============
if TYPE 1 and version < 5, then don't save this object, other case = save it
6FD768CA |> 837C24 1C 01 |CMP DWORD PTR SS:[ESP+1C],1 ; TYPE = 1 ? 6FD768CF |. 75 07 |JNZ SHORT D2Common.6FD768D8 ; TYPE <> 1 ==> goto SAVE_OBJECT 6FD768D1 |. 837C24 14 04 |CMP DWORD PTR SS:[ESP+14],4 ; VERSION = 4 ? 6FD768D6 |. 7E 27 |JLE SHORT D2Common.6FD768FF ; VERSION <= 4 ==> goto NEXT_OBJECT
SAVE_OBJECT : ============= 6FD768D8 |> 83F8 FF |CMP EAX,-1 ; ID = -1 ? 6FD768DB |. 74 22 |JE SHORT D2Common.6FD768FF ; ID = -1 ==> goto NEXT_OBJECT
6FD768DD |. 52 |PUSH EDX ; PUSH Y 6FD768DE |. 8B5424 14 |MOV EDX,DWORD PTR SS:[ESP+14] ; EDX = VERSION 6FD768E2 |. 51 |PUSH ECX ; PUSH X 6FD768E3 |. 52 |PUSH EDX ; PUSH VERSION 6FD768E4 |. 50 |PUSH EAX ; PUSH ID 6FD768E5 |. 8B4424 2C |MOV EAX,DWORD PTR SS:[ESP+2C] ; ID = NEW_ID 6FD768E9 |. 50 |PUSH EAX ; PUSH ID 6FD768EA |. 33D2 |XOR EDX,EDX ; EDX = 0 6FD768EC |. 33C9 |XOR ECX,ECX ; ECX = 0
6FD768EE |. E8 5D26FFFF |CALL D2Common.6FD68F50 ; call that function ? : ; new OBJECT(ID, ID, VERSION, X, Y);
=====================================================================================================
I'm not sure, but it should be ok
6FD68F50 /$ 56 PUSH ESI ; save ESI 6FD68F51 |. 57 PUSH EDI ; save EDI 6FD68F52 |. 8BC2 MOV EAX,EDX ; EAX = 0 6FD68F54 |. 8BF1 MOV ESI,ECX ; ESI = 0 6FD68F56 |. 6A 00 PUSH 0 ; PUSH 0 6FD68F58 |. 68 AC030000 PUSH 3AC ; PUSH 940 6FD68F5D |. 68 3030DD6F PUSH D2Common.6FDD3030 ; ASCII "C:\Projects\Diablo2\Source\D2Common\DRLG\DrlgRoom.cpp" 6FD68F62 |. BA 20000000 MOV EDX,20 ; EDX = 32 6FD68F67 |. 8BC8 MOV ECX,EAX ; ECX = 0 6FD68F69 |. E8 0AAA0400 CALL <JMP.&Fog.#10045> ; allocate 8 dwords 6FD68F6E |. 8BD0 MOV EDX,EAX ; OBJ_MEM = EAX 6FD68F70 |. B9 08000000 MOV ECX,8 ; ECX = 8 6FD68F75 |. 33C0 XOR EAX,EAX ; EAX = 0 6FD68F77 |. 8BFA MOV EDI,EDX ; EDI = OBJ_MEM 6FD68F79 |. F3:AB REP STOS DWORD PTR ES:[EDI] ; copy 8 dwords 6FD68F7B |. 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C] ; EAX = NEW_ID 6FD68F7F |. 8B4C24 10 MOV ECX,DWORD PTR SS:[ESP+10] ; ECX = LookUp 6FD68F83 |. 8902 MOV DWORD PTR DS:[EDX],EAX ; OBJ_MEM->ID = NEW_ID 6FD68F85 |. 8B4424 14 MOV EAX,DWORD PTR SS:[ESP+14] ; EAX = VERSION 6FD68F89 |. 894A 04 MOV DWORD PTR DS:[EDX+4],ECX ; OBJ_MEM->LOOK_UP = LookUp 6FD68F8C |. 8B4C24 18 MOV ECX,DWORD PTR SS:[ESP+18] ; ECX = X 6FD68F90 |. 8942 08 MOV DWORD PTR DS:[EDX+8],EAX ; OBJ_MEM->VERSION = VERSION 6FD68F93 |. 8B4424 1C MOV EAX,DWORD PTR SS:[ESP+1C] ; EAX = Y 6FD68F97 |. 85F6 TEST ESI,ESI ; ESI positive ? 6FD68F99 |. 894A 0C MOV DWORD PTR DS:[EDX+C],ECX ; OBJ_MEM->X = X 6FD68F9C |. 8942 10 MOV DWORD PTR DS:[EDX+10],EAX ; OBJ_MEM->Y = Y 6FD68F9F |. 74 16 JE SHORT D2Common.6FD68FB7 ; ESI = 0 ==> goto END_ESI_0
6FD68FA1 |. 8B8E CC000000 MOV ECX,DWORD PTR DS:[ESI+CC] ; ECX = ? 6FD68FA7 |. 5F POP EDI ; restore EDI 6FD68FA8 |. 894A 1C MOV DWORD PTR DS:[EDX+1C],ECX ; OBJ_MEM->NEXT_PTR = ? 6FD68FAB |. 8996 CC000000 MOV DWORD PTR DS:[ESI+CC],EDX ; ? = OBJ_MEM 6FD68FB1 |. 8BC2 MOV EAX,EDX ; EAX = OBJ_MEM 6FD68FB3 |. 5E POP ESI ; restore ESI 6FD68FB4 |. C2 1400 RETN 14 ; free 5 dwords and RETURN
END_ESI_0 : =========== 6FD68FB7 |> 5F POP EDI ; restore EDI 6FD68FB8 |. C742 1C 00000000 MOV DWORD PTR DS:[EDX+1C],0 ; OBJ_MEM-> = 0 6FD68FBF |. 8BC2 MOV EAX,EDX ; EAX = OBJ_MEM 6FD68FC1 |. 5E POP ESI ; restore ESI 6FD68FC2 \. C2 1400 RETN 14 ; free 5 dwords and RETURN
=====================================================================================================
add a new object in front of the current linked objects
6FD768F3 |. 8B4B 54 |MOV ECX,DWORD PTR DS:[EBX+54] ; get START_OBJ_PTR 6FD768F6 |. 8948 1C |MOV DWORD PTR DS:[EAX+1C],ECX ; CUR_OBJ_PTR->NEXT = START_OBJ_PTR 6FD768F9 |. 8943 54 |MOV DWORD PTR DS:[EBX+54],EAX ; START_OBJ_PTR = CUR_OBJ_PTR 6FD768FC |. 0978 14 |OR DWORD PTR DS:[EAX+14],EDI ; CUR_OBJ_PTR->FLAG |= EDI
NEXT_OBJECT : ============= 6FD768FF |> 8B4424 24 |MOV EAX,DWORD PTR SS:[ESP+24] ; 6FD76903 |. BD 02000000 |MOV EBP,2 ; EBP = 2 6FD76908 |. 48 |DEC EAX ; 6FD76909 |. 894424 24 |MOV DWORD PTR SS:[ESP+24],EAX ; OBJ_NUM-- 6FD7690D |.^0F85 E4FDFFFF \JNZ D2Common.6FD766F7 ; OBJ_NUM <> 0 ==> goto READ_OBJECT
_________________ DT1 Tools - DS1 Editor - MPQ list file - Extracting D2 Animation tutorial
"Sorry I can't give you offsets or anything, my dlls are always very mutant compared to what's in the release" - Isolde, aka Peter Hu, 30 Jun 2002
Last edited by Paul Siramy on Sun Nov 24, 2002 7:56 am, edited 2 times in total.
|
|
| Top |
|
 |
|
Paul Siramy
|
Posted: Fri Nov 22, 2002 3:36 am Post subject: |
|
Age: 35 Joined: Sat May 25, 2002 2:39 pm Posts: 2738 Location: La Garenne Colombes (near Paris) Gender:
|
UNKNOWN DATA / NPC PATHS :
======================================================================================================== UNKNOWN DATAS relative to the UNKNOWN layer (when UNK_TYPE is 1 or 2).
The Unknown layer can be present since version 10, but theses datas can be present only since version 12, careful. ========================================================================================================
END_OBJECTS : ============= 6FD76913 |> 8B7C24 14 MOV EDI,DWORD PTR SS:[ESP+14] ; EDI = VERSION 6FD76917 |. 83FF 0C CMP EDI,0C ; VERSION = 12 ? 6FD7691A |. 0F8C 96000000 JL D2Common.6FD769B6 ; VERSION < 12 ==> goto NPC_DATAS
; else here VERSION >= 12
6FD76920 |. 8B03 MOV EAX,DWORD PTR DS:[EBX] ; EAX = UNK_TYPE 6FD76922 |. 85C0 TEST EAX,EAX ; UNK_TYPE positive ? 6FD76924 |. 0F8E 8C000000 JLE D2Common.6FD769B6 ; UNK_TYPE <= 0 ==> goto NPC_DATAS 6FD7692A |. 3BC5 CMP EAX,EBP ; UNK_TYPE = 2 ? 6FD7692C |. 0F8F 84000000 JG D2Common.6FD769B6 ; UNK_TYPE > 2 ==> goto NPC_DATAS 6FD76932 |. 83FF 12 CMP EDI,12 ; VERSION = 18 ? 6FD76935 |. 7C 03 JL SHORT D2Common.6FD7693A ; VERSION < 18 ==> goto NO_SKIP
; else here VERSION >= 18 and UNK_TYPE is 1 or 2
6FD76937 |. 83C6 04 ADD ESI,4 ; move pointer to next data ; (skip what ? a zero it seems) NO_SKIP : ========= ; here VERSION >= 12 and UNK_TYPE is 1 or 2
6FD7693A |> 8B16 MOV EDX,DWORD PTR DS:[ESI] ; EDX = UNK_NUM 6FD7693C |. 6A 00 PUSH 0 ; PUSH 0 6FD7693E |. 8BC2 MOV EAX,EDX ; EAX = UNK_NUM 6FD76940 |. 8953 4C MOV DWORD PTR DS:[EBX+4C],EDX ; save UNK_NUM 6FD76943 |. 68 84050000 PUSH 584 ; PUSH 1412 6FD76948 |. 68 EC46DD6F PUSH D2Common.6FDD46EC ; ASCII "C:\Projects\Diablo2\Source\D2Common\DRLG\Preset.cpp" 6FD7694D |. 8D1440 LEA EDX,DWORD PTR DS:[EAX+EAX*2] ; UNK_SIZE = UNK_NUM * 3 6FD76950 |. 33C9 XOR ECX,ECX ; ECX = 0 6FD76952 |. C1E2 03 SHL EDX,3 ; UNK_SIZE == UNK_NUM * 3 * 8 6FD76955 |. 83C6 04 ADD ESI,4 ; move pointer to next data 6FD76958 |. E8 1BD00300 CALL <JMP.&Fog.#10045> ; allocate UNK_NUM * 6 dwords ; (table of UNK_NUM elements of UNK_STRUCT)
6FD7695D |. 8943 50 MOV DWORD PTR DS:[EBX+50],EAX ; UNK_PTR = EAX 6FD76960 |. 8B43 4C MOV EAX,DWORD PTR DS:[EBX+4C] ; EAX = UNK_NUM 6FD76963 |. 33C9 XOR ECX,ECX ; UNK_COUNTER = 0 6FD76965 |. 85C0 TEST EAX,EAX ; UNK_NUM positive ? 6FD76967 |. 7E 4D JLE SHORT D2Common.6FD769B6 ; UNK_NUM <= 0 ==> goto NPC_DATAS 6FD76969 |. 33C0 XOR EAX,EAX ; IDX = 0
START_UNK_DATA : ================ 6FD7696B |> 8B53 50 /MOV EDX,DWORD PTR DS:[EBX+50] ; EDX = UNK_PTR 6FD7696E |. 8B2E |MOV EBP,DWORD PTR DS:[ESI] ; EBP = DW_1 6FD76970 |. 83C6 04 |ADD ESI,4 ; move pointer to next data 6FD76973 |. 892C10 |MOV DWORD PTR DS:[EAX+EDX],EBP ; UNK_STRUCT[IDX]->DW_1 = DW_1
6FD76976 |. 8B53 50 |MOV EDX,DWORD PTR DS:[EBX+50] ; EDX = UNK_PTR 6FD76979 |. 8B2E |MOV EBP,DWORD PTR DS:[ESI] ; EBP = DW_2 6FD7697B |. 83C6 04 |ADD ESI,4 ; move pointer to next data 6FD7697E |. 896C10 04 |MOV DWORD PTR DS:[EAX+EDX+4],EBP ; UNK_STRUCT[IDX]->DW_2 = DW_2
6FD76982 |. 8B53 50 |MOV EDX,DWORD PTR DS:[EBX+50] ; EDX = UNK_PTR 6FD76985 |. 8B2E |MOV EBP,DWORD PTR DS:[ESI] ; EBP = DW_3 6FD76987 |. 83C6 04 |ADD ESI,4 ; move pointer to next data 6FD7698A |. 896C10 08 |MOV DWORD PTR DS:[EAX+EDX+8],EBP ; UNK_STRUCT[IDX]->DW_3 = DW_3
6FD7698E |. 8B53 50 |MOV EDX,DWORD PTR DS:[EBX+50] ; EDX = UNK_PTR 6FD76991 |. 8B2E |MOV EBP,DWORD PTR DS:[ESI] ; EBP = DW_4 6FD76993 |. 83C6 04 |ADD ESI,4 ; move pointer to next data 6FD76996 |. 83FF 0D |CMP EDI,0D ; VERSION = 13 ? 6FD76999 |. 896C10 0C |MOV DWORD PTR DS:[EAX+EDX+C],EBP ; UNK_STRUCT[IDX]->DW_4 = DW_4 6FD7699D |. 7C 0C |JL SHORT D2Common.6FD769AB ; VERSION < 13 ==> goto NO_DW_5
; else here VERSION >= 13 and UNK_TYPE is 1 or 2
6FD7699F |. 8B53 50 |MOV EDX,DWORD PTR DS:[EBX+50] ; EDX = UNK_PTR 6FD769A2 |. 8B2E |MOV EBP,DWORD PTR DS:[ESI] ; EBP = DW_5 6FD769A4 |. 83C6 04 |ADD ESI,4 ; move pointer to next data 6FD769A7 |. 896C10 14 |MOV DWORD PTR DS:[EAX+EDX+14],EBP ; UNK_STRUCT[IDX]->DW_5 = DW_5
NO_DW_5 : ========= 6FD769AB |> 8B53 4C |MOV EDX,DWORD PTR DS:[EBX+4C] ; EDX = UNK_NUM 6FD769AE |. 41 |INC ECX ; UNK_COUNTER ++ 6FD769AF |. 83C0 18 |ADD EAX,18 ; IDX ++ (next UNK_STRUCT) 6FD769B2 |. 3BCA |CMP ECX,EDX ; UNK_COUNTER = UNK_NUM ? 6FD769B4 |.^7C B5 \JL SHORT D2Common.6FD7696B ; UNK_COUNTER < UNK_NUM ==> goto START_UNK_DATA
============================================================================================================ now we're on the NPC PATHS datas (only present since version 14)
Format of npc paths datas (in the ds1 file) : dword = NPC_NUM then NPC_NUM datas structured like : dword = PATH_NUM dword = OBJ_X dword = OBJ_Y then PATH_NUM datas structured like : dword = PATH_X dword = PATH_Y dword = ACTION (only present since version 15... that means than in version 14 it's always 1) ============================================================================================================
NPC_DATAS : =========== 6FD769B6 |> 83FF 0E CMP EDI,0E ; VERSION = 14 ? 6FD769B9 |. 7C 53 JL SHORT D2Common.6FD76A0E ; VERSION < 14 ==> goto END_OF_LOAD 6FD769BB |. 8B06 MOV EAX,DWORD PTR DS:[ESI] ; EAX = NPC_NUM 6FD769BD |. 83C6 04 ADD ESI,4 ; move pointer to next data 6FD769C0 |. 85C0 TEST EAX,EAX ; NPC_NUM positive ? 6FD769C2 |. 7E 4A JLE SHORT D2Common.6FD76A0E ; NPC_NUM <= 0 ==> END_OF_LOAD 6FD769C4 |. 894424 24 MOV DWORD PTR SS:[ESP+24],EAX ; save NPC_NUM
START_NEW_NPC : =============== 6FD769C8 |> 8B2E MOV EBP,DWORD PTR DS:[ESI] ; EBP = PATH_NUM 6FD769CA |. 8B46 04 MOV EAX,DWORD PTR DS:[ESI+4] ; EAX = OBJ_X 6FD769CD |. 83C6 04 ADD ESI,4 ; move pointer to next data 6FD769D0 |. 83C6 04 ADD ESI,4 ; move pointer to next_data 6FD769D3 |. 8B0E MOV ECX,DWORD PTR DS:[ESI] ; ECX = OBJ_Y 6FD769D5 |. 83C6 04 ADD ESI,4 ; move pointer to next data 6FD769D8 |. 85ED TEST EBP,EBP ; PATH_NUM positive ? 6FD769DA |. 74 27 JE SHORT D2Common.6FD76A03 ; PATH_NUM = 0 ==> goto NEXT_NPC
; else here we'll read PATH_NUM datas
6FD769DC |. 8B7B 54 MOV EDI,DWORD PTR DS:[EBX+54] ; CUR_OBJ_PTR = START_OBJ_PTR 6FD769DF |. 85FF TEST EDI,EDI ; CUR_OBJ_PTR = NULL ? 6FD769E1 |. 74 11 JE SHORT D2Common.6FD769F4 ; CUR_OBJ_PTR = NULL ==> goto OBJ_NOT_FOUND
TRY_THIS_OBJ : ============== 6FD769E3 |> 3947 0C /CMP DWORD PTR DS:[EDI+C],EAX ; CUR_OBJ_PTR->X = OBJ_X ? 6FD769E6 |. 75 05 |JNZ SHORT D2Common.6FD769ED ; CUR_OBJ_PTR->X <> OBJ_X ==> goto NEXT_OBJ 6FD769E8 |. 394F 10 |CMP DWORD PTR DS:[EDI+10],ECX ; CUR_OBJ_PTR->Y = OBJ_Y ? 6FD769EB |. 74 2B |JE SHORT D2Common.6FD76A18 ; CUR_OBJ_PTR->Y = OBJ_Y ==> goto ADD_PATHS
NEXT_OBJ : ========== 6FD769ED |> 8B7F 1C |MOV EDI,DWORD PTR DS:[EDI+1C] ; EDI = CUR_OBJ_PTR->NEXT 6FD769F0 |. 85FF |TEST EDI,EDI ; CUR_OBJ_PTR->NEXT = NULL ? 6FD769F2 |.^75 EF \JNZ SHORT D2Common.6FD769E3 ; CUR_OBJ_PTR->NEXT <> NULL ==> goto TRY_THIS_OBJ
OBJ_NOT_FOUND : ===============
It appear that in the case of NPC paths with incorect object X & Y reference, we don't alert the user, we just skip theses incorrect paths datas.
6FD769F4 |> 8B4424 14 MOV EAX,DWORD PTR SS:[ESP+14] ; EAX = VERSION 6FD769F8 |. 8D34EE LEA ESI,DWORD PTR DS:[ESI+EBP*8] ; ESI += PATH_NUM * 8 (skip all PATH X and Y) 6FD769FB |. 83F8 0F CMP EAX,0F ; VERSION = 15 ? 6FD769FE |. 7C 03 JL SHORT D2Common.6FD76A03 ; VERSION < 15 ==> goto NEXT_NPC
; else here VERSION >= 15
6FD76A00 |. 8D34AE LEA ESI,DWORD PTR DS:[ESI+EBP*4] ; ESI += PATH_NUM * 4 (skip all PATH ACTION)
NEXT_NPC : ========== 6FD76A03 |> 8B4424 24 MOV EAX,DWORD PTR SS:[ESP+24] ; 6FD76A07 |. 48 DEC EAX ; 6FD76A08 |. 894424 24 MOV DWORD PTR SS:[ESP+24],EAX ; NPC_NUM -- 6FD76A0C |.^75 BA JNZ SHORT D2Common.6FD769C8 ; NPC_NUM <> 0 ==> goto START_NEW_NPC
END_OF_LOAD : ============= 6FD76A0E |> 5F POP EDI ; restore EDI 6FD76A0F |. 5E POP ESI ; restore ESI 6FD76A10 |. 5D POP EBP ; restore EBP 6FD76A11 |. 5B POP EBX ; restore EBX 6FD76A12 |. 83C4 18 ADD ESP,18 ; free local variables except the last one 6FD76A15 |. C2 0400 RETN 4 ; free last local variable ; from SVR : Pascal Calling ???
ADD_PATHS : ===========
We can only be here if CUR_OBJ_PTR is not NULL. But just for safety, we test for it again. If NULL, then we'll skip these paths data, without alerting the user (hey, it's impossible to have the pointer to NULL after all).
6FD76A18 |> 85FF TEST EDI,EDI ; CUR_OBJ_PTR = NULL ? 6FD76A1A |.^74 D8 JE SHORT D2Common.6FD769F4 ; CUR_OBJ_PTR = NULL ==> goto OBJ_NOT_FOUND
; else here we have an OBJECT to add PATHS
6FD76A1C |. 6A 00 PUSH 0 ; PUSH 0 6FD76A1E |. 68 B6050000 PUSH 5B6 ; PUSH 1462 6FD76A23 |. 68 EC46DD6F PUSH D2Common.6FDD46EC ; ASCII "C:\Projects\Diablo2\Source\D2Common\DRLG\Preset.cpp" 6FD76A28 |. BA 08000000 MOV EDX,8 ; EDX = 8 6FD76A2D |. 33C9 XOR ECX,ECX ; ECX = 0 6FD76A2F |. E8 44CF0300 CALL <JMP.&Fog.#10045> ; allocate PATHS_INFO of 1 object
6FD76A34 |. 8D546D 00 LEA EDX,DWORD PTR SS:[EBP+EBP*2] ; EDX = PATH_NUM * 3 6FD76A38 |. 33C9 XOR ECX,ECX ; ECX = 0 6FD76A3A |. 6A 00 PUSH 0 ; PUSH 0 6FD76A3C |. 68 B7050000 PUSH 5B7 ; PUSH 1463 6FD76A41 |. 68 EC46DD6F PUSH D2Common.6FDD46EC ; ASCII "C:\Projects\Diablo2\Source\D2Common\DRLG\Preset.cpp" 6FD76A46 |. 8947 18 MOV DWORD PTR DS:[EDI+18],EAX ; CUR_OBJ_PTR->PATH_PTR = EAX 6FD76A49 |. C1E2 02 SHL EDX,2 ; EDX = PATH_NUM * sizeof(ACTION) (* 12) 6FD76A4C |. E8 27CF0300 CALL <JMP.&Fog.#10045> ; allocate table of PATH_NUM ACTION struct 6FD76A51 |. 8B4F 18 MOV ECX,DWORD PTR DS:[EDI+18] ; ECX = CUR_OBJ_PTR->PATH_PTR 6FD76A54 |. 85ED TEST EBP,EBP ; PATH_NUM positive ? 6FD76A56 |. 8941 04 MOV DWORD PTR DS:[ECX+4],EAX ; PATH_PTR->ACTION_PTR = EAX 6FD76A59 |. 8B57 18 MOV EDX,DWORD PTR DS:[EDI+18] ; EDX = CUR_OBJ_PTR->PATH_PTR 6FD76A5C |. 892A MOV DWORD PTR DS:[EDX],EBP ; PATH_PTR->ACTION_NUM = PATH_NUM 6FD76A5E |.^7E A3 JLE SHORT D2Common.6FD76A03 ; PATH_NUM <= 0 ==> goto NEXT_NPC
6FD76A60 |. 8B4C24 14 MOV ECX,DWORD PTR SS:[ESP+14] ; ECX = VERSION 6FD76A64 |. 33C0 XOR EAX,EAX ; IDX = 0 6FD76A66 |. 896C24 2C MOV DWORD PTR SS:[ESP+2C],EBP ; TMP = PATH_NUM
LOAD_PATH : ===========
6FD76A6A |> 8B57 18 /MOV EDX,DWORD PTR DS:[EDI+18] ; EDX = CUR_OBJ_PTR->PATH_PTR 6FD76A6D |. 8B2E |MOV EBP,DWORD PTR DS:[ESI] ; EBP = PATH_X 6FD76A6F |. 83C6 04 |ADD ESI,4 ; move pointer to next data (PATH_Y) 6FD76A72 |. 8B52 04 |MOV EDX,DWORD PTR DS:[EDX+4] ; EDX = PATH_PTR->ACTION_PTR 6FD76A75 |. 83C6 04 |ADD ESI,4 ; move pointer to next data (ACTION if VERSION >= 15) 6FD76A78 |. 83F9 0F |CMP ECX,0F ; VERSION = 15 ? 6FD76A7B |. 896C02 04 |MOV DWORD PTR DS:[EDX+EAX+4],EBP ; ACTION_PTR[IDX]->PATH_X = PATH_X
6FD76A7F |. 8B57 18 |MOV EDX,DWORD PTR DS:[EDI+18] ; EDX = CUR_OBJ_PTR->PATH_PTR 6FD76A82 |. 8B6E FC |MOV EBP,DWORD PTR DS:[ESI-4] ; EBP = PATH_Y 6FD76A85 |. 8B52 04 |MOV EDX,DWORD PTR DS:[EDX+4] ; EDX = PATH_PTR->ACTION_PTR 6FD76A88 |. 896C02 08 |MOV DWORD PTR DS:[EDX+EAX+8],EBP ; ACTION_PTR[IDX]->PATH_Y = PATH_Y
6FD76A8C |. 8B57 18 |MOV EDX,DWORD PTR DS:[EDI+18] ; EDX = CUR_OBJ_PTR->PATH_PTR 6FD76A8F |. 8B52 04 |MOV EDX,DWORD PTR DS:[EDX+4] ; EDX = PATH_PTR->ACTION_PTR 6FD76A92 |. 7C 0A |JL SHORT D2Common.6FD76A9E ; VERSION < 15 ==> goto DEFAULT_ACTION
; else here VERSION >= 15
6FD76A94 |. 8B2E |MOV EBP,DWORD PTR DS:[ESI] ; EBP = ACTION 6FD76A96 |. 83C6 04 |ADD ESI,4 ; move pointer to next data 6FD76A99 |. 892C02 |MOV DWORD PTR DS:[EDX+EAX],EBP ; ACTION_PTR[IDX]->ACTION = ACTION 6FD76A9C |. EB 07 |JMP SHORT D2Common.6FD76AA5 ; goto ACTION_OK
DEFAULT_ACTION : ================ 6FD76A9E |> C70402 01000000 |MOV DWORD PTR DS:[EDX+EAX],1 ; ACTION_PTR[IDX]->ACTION = 1
ACTION_OK : =========== 6FD76AA5 |> 8B5424 2C |MOV EDX,DWORD PTR SS:[ESP+2C] ; 6FD76AA9 |. 83C0 0C |ADD EAX,0C ; IDX++ 6FD76AAC |. 4A |DEC EDX ; 6FD76AAD |. 895424 2C |MOV DWORD PTR SS:[ESP+2C],EDX ; TMP-- 6FD76AB1 |.^75 B7 \JNZ SHORT D2Common.6FD76A6A ; TMP <> 0 ==> goto LOAD_PATH 6FD76AB3 \.^E9 4BFFFFFF JMP D2Common.6FD76A03 ; goto NEXT_NPC
_________________ DT1 Tools - DS1 Editor - MPQ list file - Extracting D2 Animation tutorial
"Sorry I can't give you offsets or anything, my dlls are always very mutant compared to what's in the release" - Isolde, aka Peter Hu, 30 Jun 2002
|
|
| Top |
|
 |
|
Paul Siramy
|
Posted: Sun Nov 24, 2002 7:54 am Post subject: |
|
Age: 35 Joined: Sat May 25, 2002 2:39 pm Posts: 2738 Location: La Garenne Colombes (near Paris) Gender:
|
I must have been blind when I found the unknown layer & the unknown data between the objects & the npc paths. I just found what they're used for. The 2nd datas are X & Y position of groups in the Group Layer, and it have their Width & Height too.
Let's take an exemple : Data\Global\Tiles\Expansion\Siege\5x1barricade_brk_rules.ds1
Layer GROUPS TAGS =================
\ X| Y \ | 0 1 2 3 4 5 --- + -------- -------- -------- -------- -------- -------- 0 | 00000001 00000000 00000000 00000000 00000000 00000000 1 | 00000001 00000000 00000000 00000000 00000000 00000000 2 | 00000001 00000000 00000000 00000000 00000000 00000000 3 | 00000001 00000000 00000000 00000000 00000000 00000000 4 | 00000001 00000000 00000000 00000000 00000000 00000000 5 | 00000000 00000000 00000000 00000000 00000000 00000000 6 | 00000004 00000000 00000000 00000000 00000000 00000000 7 | 00000004 00000000 00000000 00000000 00000000 00000000 8 | 00000004 00000000 00000000 00000000 00000000 00000000 9 | 00000004 00000000 00000000 00000000 00000000 00000000 10 | 00000004 00000000 00000000 00000000 00000000 00000000 11 | 00000000 00000000 00000000 00000000 00000000 00000000 12 | 0000000A 00000000 00000000 00000000 00000000 00000000 13 | 0000000A 00000000 00000000 00000000 00000000 00000000 14 | 0000000A 00000000 00000000 00000000 00000000 00000000 15 | 0000000A 00000000 00000000 00000000 00000000 00000000 16 | 0000000A 00000000 00000000 00000000 00000000 00000000 17 | 00000000 00000000 00000000 00000000 00000000 00000000 18 | 00000013 00000000 00000000 00000000 00000000 00000000 19 | 00000013 00000000 00000000 00000000 00000000 00000000 20 | 00000013 00000000 00000000 00000000 00000000 00000000 21 | 00000013 00000000 00000000 00000000 00000000 00000000 22 | 00000013 00000000 00000000 00000000 00000000 00000000 23 | 00000000 00000000 00000000 00000000 00000000 00000000 24 | 0000001F 0000001F 0000001F 0000001F 0000001F 00000000 25 | 00000000 00000000 00000000 00000000 00000000 00000000 26 | 00000028 00000028 00000028 00000028 00000028 00000000 27 | 00000000 00000000 00000000 00000000 00000000 00000000 28 | 0000002D 0000002D 0000002D 0000002D 0000002D 00000000 29 | 00000000 00000000 00000000 00000000 00000000 00000000 30 | 00000032 00000032 00000032 00000032 00000032 00000000
GROUPS DEFINITION : 8 groups
Num Tile X Tile Y Width Height ? ---- -------- -------- -------- -------- -------- 1 0 30 5 1 14 2 0 28 5 1 14 3 0 26 5 1 14 4 0 24 5 1 14 5 0 18 1 5 14 6 0 12 1 5 14 7 0 6 1 5 14 8 0 0 1 5 14
Now, for each groups define in the precedent data, we read the corresponding tags :
Num Tag ---- ---- 1 032 2 02D 3 028 4 01F 5 013 6 00A 7 004 8 001
There are 2 ways to understand the relations between the layer and the definitions.
Imagine that the user is in my ds1 editor, where it see each tiles. When moving the mouse over the tiles of that map, the program know immediatly (by checking the Tag at that Tile position) if that tile is part of a Group (if tag = 0 then not part of a group). If the Tile is part of a group, the Tag in itself is useless, because we'll check all the Groups Definition structure and compare the Tile position with the area of the groups in there. The mouse is on the Tile 1, 24. The Tag is 1F, so we're on a group. Which one ? By checking the Definition structure, we'll find that this tile fit in the area # 4 : (0, 24) ---> (4, 24). And we find another data then : the last column which is always set to 14 in that ds1, but can be another values in other ds1.
The other way to use it is by taking an area. We can then check the GROUPS layer and deduce its Tag value (problem : by this method several tags can be found for 1 area).
Now, what all these datas are used for ? Two solutions :
- either they have some meaning in the Level Editor of Blizzard, to help to select a group for instance, but are not used by the game anymore (we already have such useless datas : the file strings in the header, where some old ds1 use files with .TG1 and not .DT1 extension).
- Or the other solution is that these datas are still used by the game, and therefore for what ? I think of some miscelaneous gfx that appear randomly, like Trees, corpse. I have the intuition that theses datas are useless... but I need to made some tests for that.
Btw, corected an error : the Type 1 lookup table is not ACT * 75 dwords, but ACT * 60.
_________________ DT1 Tools - DS1 Editor - MPQ list file - Extracting D2 Animation tutorial
"Sorry I can't give you offsets or anything, my dlls are always very mutant compared to what's in the release" - Isolde, aka Peter Hu, 30 Jun 2002
|
|
| Top |
|
 |
|
Hammerman
|
Posted: Sun Nov 24, 2002 3:07 pm Post subject: |
|
 |
| Champion of the Light |
Joined: Sun Jun 02, 2002 2:08 am Posts: 263 Gender:
|
Whoa, excellent post! Although it's not surprising that a post like this about ds1 files comes from you 
|
|
| Top |
|
 |
|
Myhrginoc
|
Posted: Sun Nov 24, 2002 6:37 pm Post subject: |
|
Age: 54 Joined: Sat May 25, 2002 7:28 am Posts: 12058 Location: Percussion U Gender:
|
|
Excellent work, Paul! There is so much information here, it will probably be next year before I understand it all. I am sure the next version of your editor will be a formidable tool, even in comparison with your current version!
_________________ Do the right thing. It will gratify some people and astonish the rest. ~ Mark Twain Run Diablo II in any version for mods: tutorial The Terms of Service!! Know them, abide by them, and enjoy the forums at peace. The Beginner's Guide v1.4: (MS Word | PDF) || Mod Running Scripts || TFW: Awakening
|
|
| Top |
|
 |
|
Paul Siramy
|
Posted: Sun Nov 24, 2002 6:42 pm Post subject: |
|
Age: 35 Joined: Sat May 25, 2002 2:39 pm Posts: 2738 Location: La Garenne Colombes (near Paris) Gender:
|
He he thanks  . What surprised me is that, despite it was the first time I try to decode an asm listing, it was not really that difficult in fact. But I'm glad that SVR was with me on that deciphering, it really need both of us to achieve this result, after near 2 weeks of hard works.
Now that I feel a lot more confident with asm, I'll work again on something else later, who know ? But I have discovered also that's it's such a time-consumed process  Hence, my congratulations goes to all our code-editing programmers here, they're great !
Edit : Btw, next year is only in 1 month 
_________________ DT1 Tools - DS1 Editor - MPQ list file - Extracting D2 Animation tutorial
"Sorry I can't give you offsets or anything, my dlls are always very mutant compared to what's in the release" - Isolde, aka Peter Hu, 30 Jun 2002
|
|
| Top |
|
 |
|
Paul Siramy
|
Posted: Mon Nov 25, 2002 7:03 am Post subject: |
|
Age: 35 Joined: Sat May 25, 2002 2:39 pm Posts: 2738 Location: La Garenne Colombes (near Paris) Gender:
|
For a better understanding of the ds1 format, here's a simple DS1 format revision history, before I make a more serious Doc.
In Version 1, here's the format :
- VERSION
- WIDTH
- HEIGHT
- 1 WALL layer
- 1 FLOOR layer
- 1 ORIENTATION layer for the WALL layer
- 1 reserved layer (not used)
- 1 SHADOW layer
version 2 introduced OBJECTS version 3 introduced FILENAMES version 4 introduced WALL_NUM, and changed the order of layers version 5 made some changes to the objects ID & TYPE version 6 introduced a FLAG data to each OBJECTS version 8 introduced ACT, and change the ORIENTATION meaning (older ds1 need convertions) version 9 introduced a jump of 2 dwords right after the FILENAMES version 10 introduced TAG_TYPE (but not used until version 12 ?) version 12 use the reserved layer, it become the TAG layer version 13 introduced an unknown dword to each GROUP version 14 canceled the jump of 2 dwords right after the FILENAMES, and introduced NPC_PATH version 15 introduced the ACTION data to each NPC_PATH version 16 introduced FLOOR_NUM version 18 introduced a jump of 1 dword at the begening of the GROUP Now ( Version 18), the format is :
- VERSION
- WIDTH
- HEIGHT
- ACT
- TAG_TYPE
- FILENAMES
- WALL_NUM
- FLOOR_NUM
- WALL_NUM (WALL + ORIENTATION) layers
- FLOOR_NUM layers of FLOOR
- 1 SHADOW layer
- optional TAG layer (only if TAG_TYPE is 1 or 2)
- OBJECTS
- optional GROUPS (only if TAG_TYPE is 1 or 2)
- NPC_PATH
Or "why my editor (and the Isilweo's one too) had problems for loading some ds1" 
_________________ DT1 Tools - DS1 Editor - MPQ list file - Extracting D2 Animation tutorial
"Sorry I can't give you offsets or anything, my dlls are always very mutant compared to what's in the release" - Isolde, aka Peter Hu, 30 Jun 2002
|
|
| Top |
|
 |
|
Page 1 of 1
|
[ 10 posts ] |
|
Who is online |
Users browsing this forum: No registered users and 0 guests |
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot post attachments in this forum
|
|
|
|
|
|